Университет Города Переславля
Программирование для Internet
 
"Мы, может быть, найдем то, чего мы как будто не ищем, а оно-то есть, что мы на самом деле ищем."
(А.А. Милн)

Лекция 7. JavaScript. Окна и фреймы

Сегодня речь пойдет о работе с окнами и фреймами. Для начала следует четко разделить эти понятия.

Окном мы будем называть независимое окно браузера, которое можно самостоятельно закрыть или наоборот, оставить открытым после закрытия первого, основного окна. Можно сказать, что все окна независимы и являются клонами одного и того же объекта.

Если Вы просматриваете этот текст с помощью браузера, Вы уже видите перед собою окно. Пример подобного окна - на рисунке справа.

Фрейм - это часть окна. Однако, в отличие от таблицы или, скажем, изображения, фрейм имеет многие свойства окна. Например, фрейм имеет собственное свойство location и, стало быть, во фрейм можно загрузить независимый документ. Обычно фреймы и используются для одновременного просмотра нескольких документов.

Фреймы На рисунке слева, во фреймы специально не загружено никаких "разумных" документов. Фреймы там просто подписаны, чтобы Вы могли четко уяснить себе что это такое. Конечно же, в любой из трех фреймов можно загруэить "разумный" документ.

Мы здесь не будем проводить разницы между обычными и плавающими фреймами (FRAME и IFRAME) т.к. разница между ними существует только для дизайнера. Методы же работы, с обоими видами фреймов, идентичны.

Как уже было сказано, фреймы обладают многими свойствами окна. Однако, их нельзя независимо создать (вне окна, они теряют смысл) или, скажем, удалить. Поэтому для фреймов не возникает проблемы существования. Если фрейм создан в некотором окне, то он будет существовать, пока существует окно.

Главное же сходство фреймов и окон заключается в том, что и туда и туда загружаются самостоятельные документы. Отсюда и общая проблема при работе и с фреймами и с окнами - проверка того, закончилась ли загрузка документа в окно/фрейм или еще продолжается.

Однако, прежде чем переходить к рассмотрению окон и фреймов, познакомимся с очень полезным видом записи URL.

Псевдопротокол javascript:...

В начале любого адреса URL, мы привыкли писать название протокола, например http:, ftp: и т.д.

Иногда, бывает полезно воспользоваться псевдопротоколом javascript:. "Псевдо" потому, что, на самом деле, это не протокол. URL такого вида не вызывают никакой загрузки документа из сети. Просто, вместо документа, будет использован результат выражения, записанного после javascript:. Если же результат вычисления этого выражения равен null, то никаких действий не производится.

Таким образом, мы можем воспользоваться таким протоколом тогда, когда мы не хотим загружать документ из сети, а хотим сформировать его прямо в своей программе.

URL такого вида можно использовать везде, где можно использовать обычный URL, т.е. в гиперссылках, при открытии окон, в параметре SRC тэга FRAME и т.д. Если нам не нужно загружать никакого документа, а нам просто нужна ссылка, при нажатии на которую, ничего не происходит (допустим, мы просто хотим обработать событие click особым образом), мы можем записать javascript:void(0) (результат равен null). Если нам нужно создать пустой документ, мы можем записать javascript:''. Если же нужен конкретный документ, после javascript: можно писать константу, переменную, вызов функции, ... все что угодно, лишь бы то, что мы написали имело строковое значение. Вот это самое значение - эта самая строка - и будет содержимым документа, который откроется при нажатии на ссылку, загрузится во фрейм и т.д.

Например:

<A HREF="javascript:void(0)">Неработающая ссылка</A>

<A HREF="javascript:''">Пустой документ</A>

<A HREF="javascript:'Hello, world!'">Документ Hello, world!</A>

Окна

Создание Окна

Начнем с того, что, когда Вы запускаете браузер, Вы, тем самым, уже создаете окно браузера (на самом деле, это делает операционная система, но мы не будем вдаваться в эти тонкости, возможно, Вам приятно ощущать свое могущество :-)

Иногда же возникает необходимость создать еще одно окно (или несколько), чтобы загрузить туда другой документ или даже поместить туда документ, сгенерированный Вашей JavaSript программой "на лету".

Для этого используется метод open объекта window.

open(url, имя окна, параметры);

первый аргумент - документ, который следует загрузить во вновь создаваемое окно. Второй - имя окна (значение свойства name нового объекта window). Третий - параметры создания окна.

Параметры создания окна:

Например:

open("http://joker.botik.ru/ip/images/window.gif","ps",
   "width=276 height=210 scrollbars=no resizable=no "+
	"menubar=no location=no status=no toolbar=no");

Как всегда, мы опускаем указание на объект window, т.к. он используется по умолчанию.

Если Вы нажмете

будет выполнена написаная выше команда, попробуйте.

Надеюсь, окно создалось благополучно.

Доступ с созданному окну

Что же мы может теперь сделать с этим окном? На самом деле, более важным является вопрос, а что мы хотим с ним сделать? Если мы хотели просто загрузить документ, что бы пользователь его посмотрел (например, рекламу фирмы "Рога и копыта"), то цель уже достигнута и больше нам ничего делать и не нужно.

Другое дело, если мы хотим, из своей программы, иметь доступ к объектам, расположенным в новом окне или, например, иметь возможность закрыть его, когда оно нам более не будет нужно.

В этом случае нам необходимо воспользоваться значением, которое возвращает метод open. С помощью этого значения, мы и будем впредь работать с вновь созданным окном.

Например:

var newWindow = open("","myWin","location=no");
newWindow.document.writeln("<H1>Hello world!</H1>Содержимое этого "+
   "окна сгенерировано <B>JavaScript</B> программой.<P>");

, что из этого получится.

Обратите внимание, что на этот раз, мы явно указали к какому окну относится document.writeln(). Если раньше, мы всегда писали просто document.writeln() (или, что тоже самое - window.document.writeln()) и это относилось к нашему текущему окну, то теперь мы явно указали, к документу какого именно окна мы обращаемся!

В этом и состоит вся "хитрость" работы с окнами. Окно - это объект. Значит, если мы укажем с каким объектом мы намерены иметь дело, мы можем использовать все свойства и методы этого объекта! Таким образом, все, что мы усеем делать со своим родным окном, можно делать и посторонним, нужно только всегда указывать с каким именно окном мы работаем.

Давайте, например, закроем недавно созданное окно. Для этого запишем:

newWindow.close();

.

Чтобы эффективно работать с окнами, нужно знать еще несколько вещей:

  1. у объекта document, тоже есть методы open и close. Первый из них следует вызывать перед тем, как начинать запись в документ методами write и writeln. Мы не делали этого раньше потому, что при создании окна, там уже есть открытый документ. Метод close следует вызывать после завершения записи. Комбинация close и, затем, open приведет к тому, что документ будет очищен и Вы сможете начинать писать в него заново;
  2. вновь созданное окно автоматически получает фокус ввода. Можно переключить фокус на любое окно с помощью метода focus() объекта window;
  3. для манипулирования окнами в объекте window имееется два полезных свойства: self - указывает на текущее окно и opener - указывает на то окно, из которого было открыто данное;
  4. для того чтобы проверить, существует ли созданное ранее окно или пользователь уже закрыл его (нажатие на X в верхнем правом углу), можно воспользоваться свойство closed объекта window.

Серия примеров

Рассмотрим серию примеров. В приведенной ниже таблице, все кнопки, в ответ на событие click, вызывают функции, записанные над ними. В правом столбце приведены комментарии. Разбирайте пожалуйста тексты функций и выполняйте примеры последовательно. Не слишком много смысла записывать что-то в еще не соданное окно.

Подготовительные операции

Создадим пустое окно. Обратите внимание, что, после его создания, оно станет активным, т.е. получит фокус.

Уничтожим созданное окно.

Создадим его снова, но при этом, сохраним текущее окно активным.

Сделаем созданное окно активным.

Выведем в созданное окно некоторый текст. Обратите внимание, там где нужны тэги, мы их так и выводим. Все срабатывает.

Допишем еще немного текста. Заметьте, мы пишем туда тэги формы и форма там появляется.

Закроем документ. Писать в него больше нельзя, он считается завершенным, но, зато, можно работать с его формой.

Запишем текст в поле ввода формы, находящейся в чужом окне. Заметьте, мы это делаем точно также как делали со своим окном. Только указываем окно!

Наберите в поле ввода постороннего окна текст, а эта функция прочитает его. И опять - ничего нового. Мы это уже делали со "своим окном".

Загрузим в порожденное окно документ http://joker.botik.ru/

Откроем документ снова. Обратите внимание, он очистился!

Запишем в него текст.

Заключительные замечания

Вот вроде бы и все про окна. Теперь Вы можете экспериментировать самостоятельно.

Остался, правда, невыясненным один вопрос: как из JavaScript программы одного окна обращаться к переменным и функциям другого?

Ответ вряд-ли покажется неожиданным. Дело в том, что функции и глобальные переменные, определенные нами в окне, есть попросту методы и свойства, добавленные нами к объекту window. А это значит, что обращаться к ним можно точно также, как к формам и другим элементам - указывая идентификатор окна перед именем функции или переменной. Например:

var newWin = open("http://www.botik.ru/","botik","");
newWin.initAll();  // обращение к функции initAll() определенной 
                   // в документе http://www.botik.ru/

Другой пример. Допустим, мы создаем сайт из нескольких страниц, которые порождают друг друга в новых окнах. Прежде чем порождающая страница начнет работать с документом в порожденном окне, хотелось бы убедиться в том, что документ в порожденном окне уже загрузился из сети. В этом случае, уместно определить в главном окне специальную переменную, которая изначально равна false. А документ порожденного окна должет присвоить ей true как только загрузится. Это могло бы выглядеть так:

В документе главного окна
var childLoaded = false;
var newWin = open("http://www.botik.ru/","botik","");

В документе порождаемого окна
<BODY ONLOAD="opener.childLoaded=true">

На самом деле, мы можем использовать любые элементы одного окна из наших программ, определенных в другом окне. Например, функции, определенные в одном документе, могут обрабатывать события происшедшие в другом.

Однако, здесь есть некоторое ограничение. Из соображений безопасности, програмам разрешается доступ только к тем окнам, документы в которых либо созданы из программы, либо загружены с того же сервера с которого загружен и документ текущего окна. Мы еще столнемся с этим ограничением в теме DHTML. Там же мы посмотрим, как с ним бороться.

Фреймы

Создание фреймов

Фреймы создаются в HTML с помощью тэга FRAME. В JavaScript доступ к фреймам осуществляется через массив frames - свойство объекта window.

Мы не будем рассматривать здесь способы описания фреймов, атрибут TARGET и т.п. Все это должно быть Вам известно из курса HTML. Если кто-то забыл, посмотрите описание HTML. Мы же сосредоточимся на доступе к фреймам из программ на JavaScript.

Работа с фреймами

Когда мы говорили об окнах, то мы отмечали, что они все равноправны. Елинственное, что связывало порожденное окно с породившим - свойство opener.

С фреймами дело обстоит иначе. Все фреймы созданные в окне, являются потомками этого окна. Если внутри фрейма загружен документ, который, в свою очередь, содержит FRAMESET то фреймы этого FRAMESET являются потомками родительского фрейма и т.д. В остальном же фреймы подобны окнам. Они обладают всеми свойствами объекта window.

Для организации связи родитель-потомок служат свойства объекта window: parent - окно-родитель (фрейм-родитель) и top - окно самого верхнего уровня.

Рассмотрим окно в котором определены следующие тэги.

<FRAMESET COLS="50%,*">
   <FRAMESET ROWS="30%,*">
      <FRAME NAME="fr1" SRC="javascript:void(0)"></FRAME>
      <FRAME NAME="fr2" SRC="javascript:void(0)"></FRAME>
   </FRAMESET>
   <FRAME NAME="fr3" SRC="javascript:void(0)"></FRAME>
</FRAMESET>

В этом окне определены три фрейма. Все они являются потомками текущего окна. Значит, все они являются элементами массива frames текущего окна. Таким образом, мы можем обращаться к ним по их именам, через массив frames, а именно frames["fr1"], frames["fr2"] и frames["fr3"].

На самом деле, поскольку их имена уникальны, можно обращаться и просто по именам, минуя массив frames - fr1, fr2 и fr3.

Ну, а что делать, если программа определенная в документе, загруженном во фрейм fr1, захочет добраться до фрейма fr2? Да, именно так, как Вы подумали, она должна обратиться к fr2 через главное окно: top.fr2 или parent.fr2, поскольку в данном случае окно - родитель одновременно является и окном самого верхнего уровня.

Ниже приведен текст некой страницы. Посмотрите и попытайтесь понять что там к чему.

<HTML>
<HEAD>
   <META HTTP-EQUIV="Content-Type"
      CONTENT="text/html; charset=windows-1251">
   <TITLE>Пример фреймов</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function writeToFrames() {
   fr1.document.write("<H1>Фрейм 1</H1>Попали?");
   fr2.document.write("<H1>Фрейм 2</H1>Попали?");
   fr3.document.write("<H1>Фрейм 3</H1>Попали?");
}
onload = writeToFrames;
</SCRIPT>  
</HEAD>
<FRAMESET COLS="50%,*">
   <FRAMESET ROWS="30%,*">
      <FRAME NAME="fr1"></FRAME>
      <FRAME NAME="fr2"></FRAME>
   </FRAMESET>
   <FRAME NAME="fr3"></FRAME>
</FRAMESET>
</HTML>

Посмотрели? Теперь загрузите ее и проверьте соответствует ли действительность Вашим ожиданиям?

Теперь, когда мы знаем как именовать фреймы и как добираться из одного в другой, мы можем делать с фреймами абсолютно все, что мы делали с окнами - писать в них, загружать в них другие документы и т.д. и т.п.

Мне осталось лишь дать маленький совет и привести еще один полезный пример.

Старайтесь размещать Ваши JavaScript функции в самом главном документе, там где у Вас находится FRAMESET. Это даст Вам уверенность, что когда бы некая функция ни понадобилась документу расположенному во фрейме, она уже будет доступна, ведь главный документ грузится из сети первым.

И последний пример. Допустим, Вы разработали страницу, состоящую из нескольких фреймов и Вам бы очень не хотелось, чтобы документы, предназначенные для показа во фреймах, кто-то загружал бы как главные - прямо в окно. Например, они при этом непонятны или еще что-нибудь.

Как с этим бороться? Очевидно, документ, предназначенный для показа во фрейме, должен проверять, а не загрузили ли его как самостоятельный? И, если так, то немедленно загружать, вместо себя, свою главную - фреймосодержащую страницу.

Для решения этой задачи, достаточно, в самом начале документов, предназначенных для показа во фреймах, расположить такой простой код:

if (self==parent) location.replace("mainpage.html");

Здесь предполагается, что главная страница называется mainpage.html.

Есть еще один, более полный (вернее, более близкий к реальной жизни) пример. Посмотрите его и попробуйте написать самостоятельно. Если же совсем не получится, разберите хотя бы его исходный текст.


До сессии всего 35 дней!!!

Главная страница Замечания? Комментарии? Идеи?